﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace NielsHebling.UnitTestResultViewerForSL.Controls
{
    public class ExtendedListView : ListView
    {
        private ExtendedGridViewColumn _lastSortedColumn;
        private ListSortDirection _lastSortDirection = ListSortDirection.Ascending;
        private ICollectionView _view;
        private double _itemHeight = 0.0;
        private ListViewItem _localItem;
        private double tempMaxHeight = 0.0;

        public bool IsFullContent
        {
            get { return (bool)GetValue(IsFullContentProperty); }
            set { SetValue(IsFullContentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsFullContent.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsFullContentProperty =
            DependencyProperty.Register("IsFullContent", typeof(bool), typeof(ExtendedListView), new PropertyMetadata(true, new PropertyChangedCallback(OnIsFullContent_PropertyChanged)));

        static void OnIsFullContent_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            GridView gridView = ((ExtendedListView)sender).View as GridView;
            if (!(bool)e.NewValue)
            {

                //Remove Columns
                for (int i = gridView.Columns.Count - 1; i >= 0; i--)
                {
                    if (!((ExtendedGridViewColumn)gridView.Columns[i]).IsFullContentColumn)
                    {
                        gridView.Columns.RemoveAt(i);
                    }
                }
            }
        }

        public bool IsFixedHeight
        {
            get { return (bool)GetValue(IsFixedHeightProperty); }
            set { SetValue(IsFixedHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsFixedHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsFixedHeightProperty =
            DependencyProperty.Register("IsFixedHeight", typeof(bool), typeof(ExtendedListView), new UIPropertyMetadata(false));


        public int MaxDisplayRows
        {
            get { return (int)GetValue(MaxDisplayRowsProperty); }
            set { SetValue(MaxDisplayRowsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MaxDisplayRows.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaxDisplayRowsProperty =
            DependencyProperty.Register("MaxDisplayRows", typeof(int), typeof(ExtendedListView), new UIPropertyMetadata(int.MaxValue));


        public double RenderedHeight
        {
            get { return (double)GetValue(RenderedHeightProperty); }
            set { SetValue(RenderedHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RenderedHeightProperty =
            DependencyProperty.Register("RenderedHeight", typeof(double), typeof(ExtendedListView), new UIPropertyMetadata(0.0, new PropertyChangedCallback(OnRenderedHeight_PropertyChanged)));

        static void OnRenderedHeight_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ExtendedListView instance = sender as ExtendedListView;
            if (Convert.ToDouble(e.NewValue) > instance.tempMaxHeight)
            {
                instance.tempMaxHeight = Convert.ToDouble(e.NewValue);
                double itemHeight = instance.tempMaxHeight + instance._localItem.Margin.Top + instance._localItem.Margin.Bottom;

                //Add one more row, because HeaderRow is also counted as a row
                //Add 3px margin
                instance.MaxHeight = (itemHeight * (instance.MaxDisplayRows + 1)) + 3;
                instance.MinHeight = (itemHeight * (instance.MaxDisplayRows + 1)) + 3;
            }
        }



        public ExtendedListView()
        {
            //this.ItemContainerStyleSelector = new ListViewItemStyleSelector();
            this.HeaderSortAscTemplate = "HeaderTemplateArrowUp";
            this.HeaderSortDescTemplate = "HeaderTemplateArrowDown";
            this.HeaderUnsortedTemplate = "HeaderTemplateUnsorted";
            this.ItemContainerGenerator.StatusChanged += new EventHandler(ItemContainerGenerator_StatusChanged);
        }

        void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
        {
            if (this.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
            {
                if (this.IsFixedHeight)
                {
                    if (this != null && this.MaxDisplayRows < int.MaxValue)
                    {
                        if (this._itemHeight == 0.0)
                        {
                            if (this.ItemContainerGenerator != null)
                            {
                                ListViewItem item = this.ItemContainerGenerator.ContainerFromIndex(0) as ListViewItem;
                                if (item != null)
                                {
                                    _localItem = item;
                                    item.SizeChanged += new SizeChangedEventHandler(item_SizeChanged);
                                    RenderedHeight = item.ActualHeight;
                                }
                            }
                        }
                    }
                }
            }
        }

        void item_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (e.HeightChanged)
            {
                RenderedHeight = e.NewSize.Height;
            }
        }


        #region Sorting
        public string HeaderSortAscTemplate
        {
            get { return (string)GetValue(HeaderSortAscTemplateProperty); }
            set { SetValue(HeaderSortAscTemplateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HeaderSortAscTemplate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderSortAscTemplateProperty =
            DependencyProperty.Register("HeaderSortAscTemplate", typeof(string), typeof(ExtendedListView), new UIPropertyMetadata(""));



        public string HeaderSortDescTemplate
        {
            get { return (string)GetValue(HeaderSortDescTemplateProperty); }
            set { SetValue(HeaderSortDescTemplateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HeaderSortDescTemplate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderSortDescTemplateProperty =
            DependencyProperty.Register("HeaderSortDescTemplate", typeof(string), typeof(ExtendedListView), new UIPropertyMetadata(""));

        public string HeaderUnsortedTemplate
        {
            get { return (string)GetValue(HeaderUnsortedTemplateProperty); }
            set { SetValue(HeaderUnsortedTemplateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HeaderUnsortedTemplate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderUnsortedTemplateProperty =
            DependencyProperty.Register("HeaderUnsortedTemplate", typeof(string), typeof(ExtendedListView), new UIPropertyMetadata(""));



        protected override void OnInitialized(EventArgs e)
        {
            this.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeaderClicked));

            GridView gridView = this.View as GridView;
            if (gridView != null)
            {
                ExtendedGridViewColumn sortableColumn = null;
                foreach (GridViewColumn col in gridView.Columns)
                {
                    sortableColumn = col as ExtendedGridViewColumn;
                    if (sortableColumn != null)
                    {
                        if (sortableColumn.IsDefaultSortColumn)
                        {
                            break;
                        }
                        sortableColumn = null;
                    }
                }

                if (sortableColumn != null)
                {
                    _lastSortedColumn = sortableColumn;
                    Sort(sortableColumn.SortProperty, ListSortDirection.Ascending);

                    if (!String.IsNullOrEmpty(this.HeaderSortAscTemplate))
                    {
                        sortableColumn.HeaderTemplate = this.TryFindResource(HeaderSortAscTemplate) as DataTemplate;
                    }
                    this.SelectedIndex = 0;
                }
            }
            base.OnInitialized(e);
        }

        public void ColumnHeaderClicked(object sender, RoutedEventArgs e)
        {
            GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;

            // ensure that we clicked on the column header and not the padding that's added to fill the space.
            if (headerClicked != null && headerClicked.Role != GridViewColumnHeaderRole.Padding)
            {
                // attempt to cast to the sortableGridViewColumn object.
                ExtendedGridViewColumn sortableGridViewColumn = (headerClicked.Column) as ExtendedGridViewColumn;

                // ensure that the column header is the correct type and a sort property has been set.
                if (sortableGridViewColumn != null && !String.IsNullOrEmpty(sortableGridViewColumn.SortProperty))
                {
                    ListSortDirection direction;
                    bool newSortColumn = false;

                    // determine if this is a new sort, or a switch in sort direction.
                    if (_lastSortedColumn == null
                        || String.IsNullOrEmpty(_lastSortedColumn.SortProperty)
                        || !String.Equals(sortableGridViewColumn.SortProperty, _lastSortedColumn.SortProperty, StringComparison.InvariantCultureIgnoreCase))
                    {
                        newSortColumn = true;
                        direction = ListSortDirection.Ascending;
                    }
                    else
                    {
                        if (_lastSortDirection == ListSortDirection.Ascending)
                        {
                            direction = ListSortDirection.Descending;
                        }
                        else
                        {
                            direction = ListSortDirection.Ascending;
                        }
                    }

                    // get the sort property name from the column's information.
                    string sortPropertyName = sortableGridViewColumn.SortProperty;
                    // Sort the data.
                    Sort(sortPropertyName, direction);
                    if (direction == ListSortDirection.Ascending)
                    {
                        if (!String.IsNullOrEmpty(this.HeaderSortAscTemplate))
                        {
                            sortableGridViewColumn.HeaderTemplate = this.TryFindResource(HeaderSortAscTemplate) as DataTemplate;
                        }
                        else
                        {
                            sortableGridViewColumn.HeaderTemplate = null;
                        }
                    }
                    else
                    {
                        if (!String.IsNullOrEmpty(this.HeaderSortDescTemplate))
                        {
                            sortableGridViewColumn.HeaderTemplate = this.TryFindResource(HeaderSortDescTemplate) as DataTemplate;
                        }
                        else
                        {
                            sortableGridViewColumn.HeaderTemplate = null;
                        }
                    }

                    // Remove arrow from previously sorted header
                    if (newSortColumn && _lastSortedColumn != null)
                    {
                        if (!String.IsNullOrEmpty(this.HeaderUnsortedTemplate))
                        {
                            _lastSortedColumn.HeaderTemplate = this.TryFindResource(HeaderUnsortedTemplate) as DataTemplate;
                        }
                        else
                        {
                            _lastSortedColumn.HeaderTemplate = null;
                        }
                    }
                    _lastSortedColumn = sortableGridViewColumn;
                }

            }
        }

        private void Sort(string sortBy, ListSortDirection direction)
        {
            try
            {
                _lastSortDirection = direction;
                _view = CollectionViewSource.GetDefaultView(this.ItemsSource);
                if (_view != null)
                {
                    _view.SortDescriptions.Clear();
                    SortDescription sd = new SortDescription(sortBy, direction);
                    _view.SortDescriptions.Add(sd);
                    _view.Refresh();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }
        }


        #endregion

        #region Grouping
        public string GroupByProperty
        {
            get { return (string)GetValue(GroupByPropertyProperty); }
            set { SetValue(GroupByPropertyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for GroupByProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty GroupByPropertyProperty =
            DependencyProperty.Register("GroupByProperty", typeof(string), typeof(ExtendedListView), new UIPropertyMetadata("", new PropertyChangedCallback(OnGroupByPropertyChanged)));


        public static void OnGroupByPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ExtendedListView instance = sender as ExtendedListView;

            if (instance._view != null)
            {
                if (e.NewValue.ToString().Length > 0)
                {
                    instance._view = CollectionViewSource.GetDefaultView(instance.ItemsSource);
                    instance._view.GroupDescriptions.Clear();
                    instance._view.GroupDescriptions.Add(new PropertyGroupDescription(e.NewValue.ToString()));
                    instance._view.Refresh();
                }
                else
                {
                    instance._view = CollectionViewSource.GetDefaultView(instance.ItemsSource);
                    instance._view.GroupDescriptions.Clear();
                    instance._view.Refresh();
                }
            }
        }

        protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
        {
            _view = CollectionViewSource.GetDefaultView(this.ItemsSource);
            if (_view != null)
            {
                if (this.GroupByProperty.Length > 0)
                {
                    _view.GroupDescriptions.Clear();
                    _view.GroupDescriptions.Add(new PropertyGroupDescription(this.GroupByProperty));
                    _view.Refresh();
                }
                else
                {
                    _view.GroupDescriptions.Clear();
                    _view.Refresh();
                }
            }
            base.OnItemsSourceChanged(oldValue, newValue);
        }
        #endregion

        #region Filtering

        #region SingleValueFilter
        public DependencyProperty FilterPropertyValue { get; set; }

        public string FilterValue
        {
            get { return (string)GetValue(FilterValueProperty); }
            set { SetValue(FilterValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for FilterBy.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FilterValueProperty =
            DependencyProperty.Register("FilterValue", typeof(string), typeof(ExtendedListView), new UIPropertyMetadata(string.Empty, new PropertyChangedCallback(OnFilterValue_PropertyChanged)));

        static void OnFilterValue_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ExtendedListView instance = sender as ExtendedListView;
            if (instance._view != null)
            {
                instance._view.Filter = new Predicate<object>(instance.FilterCallback);
            }
        }

        private bool FilterCallback(object item)
        {
            if (item is DependencyObject)
            {
                DependencyObject value = item as DependencyObject;
                ValueSearch searchReq = new ValueSearch(FilterValue, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                string cleanedValue = ValueSearch.RemoveStopWords(value.GetValue(FilterPropertyValue).ToString()).ToLower();
                if (cleanedValue.Contains(FilterValue.ToLower()))
                {
                    return true;
                }
                //if (searchReq.IsMatch(value.GetValue(FilterPropertyValue).ToString()))
                //{
                //    return true;
                //}
            }
            return false;
        }
        #endregion

        #region MultiValueFilter
        public ObservableCollection<object> MultiFilterValue
        {
            get { return (ObservableCollection<object>)GetValue(MultiFilterValueProperty); }
            set { SetValue(MultiFilterValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MultiFilterValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MultiFilterValueProperty =
            DependencyProperty.Register("MultiFilterValue", typeof(ObservableCollection<object>), typeof(ExtendedListView), new UIPropertyMetadata(new ObservableCollection<object>(), new PropertyChangedCallback(OnMultiFilterValue_PropertyChanged)));

        static void OnMultiFilterValue_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ExtendedListView instance = sender as ExtendedListView;
            if (instance._view != null)
            {
                //instance._view.Filter = new Predicate<object>(instance.MultiFilterCallback);
            }
        }

        //private bool MultiFilterCallback(object item)
        //{
        //    if (MultiFilterValue != null && MultiFilterValue.Count > 0)
        //    {
        //        if (item is Todo)
        //        {
        //            Todo value = item as Todo;
        //            if (value is Rule)
        //            {
        //                if (value is RuleIssue)
        //                {
        //                    RuleIssue ruleValue = value as RuleIssue;
        //                    if (ruleValue.Usecase.ToUpper() == "POLISHING" && MultiFilterValue.Contains(ruleValue.TypeToString))
        //                    {
        //                        return true;
        //                    }
        //                    else if (ruleValue.Usecase.ToUpper() == "VERIFICATION" && MultiFilterValue.Contains(ruleValue.TypeToString))
        //                    {
        //                        return true;
        //                    }
        //                }
        //                else if (value is RuleException)
        //                {
        //                    RuleException ruleValue = value as RuleException;
        //                    if (ruleValue.Usecase.ToUpper() == "POLISHING" && MultiFilterValue.Contains("UX Rule"))
        //                    {
        //                        return true;
        //                    }
        //                    else if (ruleValue.Usecase.ToUpper() == "VERIFICATION" && MultiFilterValue.Contains("Consistency Rule"))
        //                    {
        //                        return true;
        //                    }
        //                }
        //                else if (value is RuleIncident)
        //                {
        //                    RuleIncident ruleValue = value as RuleIncident;
        //                    if (ruleValue.Usecase.ToUpper() == "POLISHING" && MultiFilterValue.Contains("UX Rule"))
        //                    {
        //                        return true;
        //                    }
        //                    else if (ruleValue.Usecase.ToUpper() == "VERIFICATION" && MultiFilterValue.Contains("Consistency Rule"))
        //                    {
        //                        return true;
        //                    }
        //                }
        //            }
        //            else if (value is PostMigrationStep)
        //            {
        //                PostMigrationStep pms = value as PostMigrationStep;
        //                if (MultiFilterValue.Contains(pms.TypeToString))
        //                {
        //                    return true;
        //                }
        //            }
        //            else if( value is SelfDefinedTodo)
        //            {
        //                SelfDefinedTodo sdt = value as SelfDefinedTodo;
        //                if (MultiFilterValue.Contains(sdt.TypeToString))
        //                {
        //                    return true;
        //                }
        //            }
        //        }
        //    }
        //    return false;
        //}
        #endregion

        #endregion
    }   

    public class ValueSearch : Regex
    {
        public static string WildcardToRegex(string pattern)
        {
            return "^" + Regex.Escape(pattern).
            Replace("\\*", ".*").
            Replace("\\?", ".") + "$";
        }

        public ValueSearch(string pattern)
            : base(WildcardToRegex(pattern))
        {
        }

        public ValueSearch(string pattern, RegexOptions options)
            : base(WildcardToRegex(pattern), options)
        {
        }

        public static string RemoveStopWords(string text)
        {
            string[] stopwords = { "about", "above", "across", "after", "afterwards", "again", "against", "all", "almost", "alone", "along", "already", "also", "although", "always", "among", "amongst", "and", "another", "any", "anyhow", "anyone", "anything", "anywhere", "are", "around", "became", "because", "become", "becomes", "becoming", "been", "before", "beforehand", "behind", "being", "below", "beside", "besides", "between", "beyond", "both", "but", "cannot", "comprises", "corresponding", "could", "described", "desired", "does", "down", "during", "each", "either", "else", "elsewhere", "enough", "etc", "even", "ever", "every", "everyone", "everything", "everywhere", "except", "few", "first", "for", "former", "formerly", "from", "further", "generally", "had", "has", "have", "having", "hence", "her", "here", "hereafter", "hereby", "herein", "hereupon", "hers", "herself", "him", "himself", "his", "how", "however", "indeed", "into", "its", "itself", "last", "latter", "latterly", "least", "less", "many", "may", "means", "meanwhile", "might", "more", "moreover", "most", "mostly", "much", "must", "myself", "namely", "neither", "never", "nevertheless", "next", "nobody", "none", "noone", "nor", "not", "nothing", "now", "nowhere", "off", "often", "once", "one", "only", "onto", "other", "others", "otherwise", "our", "ours", "ourselves", "out", "over", "own", "particularly", "per", "perhaps", "preferably", "preferred", "present", "rather", "relatively", "respectively", "said", "same", "seem", "seemed", "seeming", "seems", "several", "she", "should", "since", "some", "somehow", "someone", "something", "sometime", "sometimes", "somewhere", "still", "such", "sitable", "than", "that", "the", "their", "them", "themselves", "then", "thence", "there", "thereafter", "thereby", "therefor", "therefore", "therein", "thereof", "thereto", "thereupon", "these", "they", "this", "those", "though", "through", "throughout", "thru", "thus", "together", "too", "toward", "towards", "under", "until", "upon", "use", "various", "very", "was", "well", "were", "what", "whatever", "whatsoever", "when", "whence", "whenever", "whensoever", "where", "whereafter", "whereas", "whereat", "whereby", "wherefrom", "wherein", "whereinto", "whereof", "whereon", "whereto", "whereunto", "whereupon", "wherever", "wherewith", "whether", "which", "whichever", "whichsoever", "while", "whilst", "whither", "who", "whoever", "whole", "whom", "whomever", "whomsoever", "whose", "whosoever", "why", "will", "with", "within", "without", "would", "yet", "you", "your", "yours", "yourself", "yourselves", ".", "\"", "\\", ":", ",", ";" };
            Dictionary<string, bool> stopWordDict = new Dictionary<string, bool>();

            foreach (string word in stopwords)
                stopWordDict.Add(word, true);

            string[] originalRemoved = Regex.Split(text, @"\W+");

            StringBuilder returnValue = new StringBuilder();

            foreach (string word in originalRemoved)
                if (!stopWordDict.ContainsKey(word.ToLower()))
                    returnValue.Append(word + " ");

            return returnValue.ToString().Trim();
        }

    }
}
